// Copyright (c) 2019-2020 Alexander Medvednikov. All rights reserved.
// Use of this source code is governed by an MIT license
// that can be found in the LICENSE file.

module factorial

const (
    log_sqrt_2pi = 9.18938533204672741780329736e-1

    b_numbers = [
        /* Bernoulli numbers B(2),B(4),B(6),...,B(20).  Only B(2),...,B(10) currently
        * used.
        */
    f64(1.0 / (6.0 * 2.0 * 1.0)),
       -1.0 / (30.0 * 4.0 * 3.0),
        1.0 / (42.0 * 6.0 * 5.0),
       -1.0 / (30.0 * 8.0 * 7.0),
        5.0 / (66.0 * 10.0 * 9.0),
       -691.0 / (2730.0 * 12.0 * 11.0),
        7.0 / (6.0 * 14.0 * 13.0),
       -3617.0 / (510.0 * 16.0 * 15.0),
        43867.0 / (796.0 * 18.0 * 17.0),
       -174611.0 / (330.0 * 20.0 * 19.0)
        ]

	factorials_table = [
    f64(1.000000000000000000000e+0),        /*   0! */
        1.000000000000000000000e+0,         /*   1! */
        2.000000000000000000000e+0,         /*   2! */
        6.000000000000000000000e+0,         /*   3! */
        2.400000000000000000000e+1,         /*   4! */
        1.200000000000000000000e+2,         /*   5! */
        7.200000000000000000000e+2,         /*   6! */
        5.040000000000000000000e+3,         /*   7! */
        4.032000000000000000000e+4,         /*   8! */
        3.628800000000000000000e+5,         /*   9! */
        3.628800000000000000000e+6,         /*  10! */
        3.991680000000000000000e+7,         /*  11! */
        4.790016000000000000000e+8,         /*  12! */
        6.227020800000000000000e+9,         /*  13! */
        8.717829120000000000000e+10,        /*  14! */
        1.307674368000000000000e+12,        /*  15! */
        2.092278988800000000000e+13,        /*  16! */
        3.556874280960000000000e+14,        /*  17! */
        6.402373705728000000000e+15,        /*  18! */
        1.216451004088320000000e+17,        /*  19! */
        2.432902008176640000000e+18,        /*  20! */
        5.109094217170944000000e+19,        /*  21! */
        1.124000727777607680000e+21,        /*  22! */
        2.585201673888497664000e+22,        /*  23! */
        6.204484017332394393600e+23,        /*  24! */
        1.551121004333098598400e+25,        /*  25! */
        4.032914611266056355840e+26,        /*  26! */
        1.088886945041835216077e+28,        /*  27! */
        3.048883446117138605015e+29,        /*  28! */
        8.841761993739701954544e+30,        /*  29! */
        2.652528598121910586363e+32,        /*  30! */
        8.222838654177922817726e+33,        /*  31! */
        2.631308369336935301672e+35,        /*  32! */
        8.683317618811886495518e+36,        /*  33! */
        2.952327990396041408476e+38,        /*  34! */
        1.033314796638614492967e+40,        /*  35! */
        3.719933267899012174680e+41,        /*  36! */
        1.376375309122634504632e+43,        /*  37! */
        5.230226174666011117600e+44,        /*  38! */
        2.039788208119744335864e+46,        /*  39! */
        8.159152832478977343456e+47,        /*  40! */
        3.345252661316380710817e+49,        /*  41! */
        1.405006117752879898543e+51,        /*  42! */
        6.041526306337383563736e+52,        /*  43! */
        2.658271574788448768044e+54,        /*  44! */
        1.196222208654801945620e+56,        /*  45! */
        5.502622159812088949850e+57,        /*  46! */
        2.586232415111681806430e+59,        /*  47! */
        1.241391559253607267086e+61,        /*  48! */
        6.082818640342675608723e+62,        /*  49! */
        3.041409320171337804361e+64,        /*  50! */
        1.551118753287382280224e+66,        /*  51! */
        8.065817517094387857166e+67,        /*  52! */
        4.274883284060025564298e+69,        /*  53! */
        2.308436973392413804721e+71,        /*  54! */
        1.269640335365827592597e+73,        /*  55! */
        7.109985878048634518540e+74,        /*  56! */
        4.052691950487721675568e+76,        /*  57! */
        2.350561331282878571829e+78,        /*  58! */
        1.386831185456898357379e+80,        /*  59! */
        8.320987112741390144276e+81,        /*  60! */
        5.075802138772247988009e+83,        /*  61! */
        3.146997326038793752565e+85,        /*  62! */
        1.982608315404440064116e+87,        /*  63! */
        1.268869321858841641034e+89,        /*  64! */
        8.247650592082470666723e+90,        /*  65! */
        5.443449390774430640037e+92,        /*  66! */
        3.647111091818868528825e+94,        /*  67! */
        2.480035542436830599601e+96,        /*  68! */
        1.711224524281413113725e+98,        /*  69! */
        1.197857166996989179607e+100,       /*  70! */
        8.504785885678623175212e+101,       /*  71! */
        6.123445837688608686152e+103,       /*  72! */
        4.470115461512684340891e+105,       /*  73! */
        3.307885441519386412260e+107,       /*  74! */
        2.480914081139539809195e+109,       /*  75! */
        1.885494701666050254988e+111,       /*  76! */
        1.451830920282858696341e+113,       /*  77! */
        1.132428117820629783146e+115,       /*  78! */
        8.946182130782975286851e+116,       /*  79! */
        7.156945704626380229481e+118,       /*  80! */
        5.797126020747367985880e+120,       /*  81! */
        4.753643337012841748421e+122,       /*  82! */
        3.945523969720658651190e+124,       /*  83! */
        3.314240134565353266999e+126,       /*  84! */
        2.817104114380550276949e+128,       /*  85! */
        2.422709538367273238177e+130,       /*  86! */
        2.107757298379527717214e+132,       /*  87! */
        1.854826422573984391148e+134,       /*  88! */
        1.650795516090846108122e+136,       /*  89! */
        1.485715964481761497310e+138,       /*  90! */
        1.352001527678402962552e+140,       /*  91! */
        1.243841405464130725548e+142,       /*  92! */
        1.156772507081641574759e+144,       /*  93! */
        1.087366156656743080274e+146,       /*  94! */
        1.032997848823905926260e+148,       /*  95! */
        9.916779348709496892096e+149,       /*  96! */
        9.619275968248211985333e+151,       /*  97! */
        9.426890448883247745626e+153,       /*  98! */
        9.332621544394415268170e+155,       /*  99! */
        9.332621544394415268170e+157,       /* 100! */
        9.425947759838359420852e+159,       /* 101! */
        9.614466715035126609269e+161,       /* 102! */
        9.902900716486180407547e+163,       /* 103! */
        1.029901674514562762385e+166,       /* 104! */
        1.081396758240290900504e+168,       /* 105! */
        1.146280563734708354534e+170,       /* 106! */
        1.226520203196137939352e+172,       /* 107! */
        1.324641819451828974500e+174,       /* 108! */
        1.443859583202493582205e+176,       /* 109! */
        1.588245541522742940425e+178,       /* 110! */
        1.762952551090244663872e+180,       /* 111! */
        1.974506857221074023537e+182,       /* 112! */
        2.231192748659813646597e+184,       /* 113! */
        2.543559733472187557120e+186,       /* 114! */
        2.925093693493015690688e+188,       /* 115! */
        3.393108684451898201198e+190,       /* 116! */
        3.969937160808720895402e+192,       /* 117! */
        4.684525849754290656574e+194,       /* 118! */
        5.574585761207605881323e+196,       /* 119! */
        6.689502913449127057588e+198,       /* 120! */
        8.094298525273443739682e+200,       /* 121! */
        9.875044200833601362412e+202,       /* 122! */
        1.214630436702532967577e+205,       /* 123! */
        1.506141741511140879795e+207,       /* 124! */
        1.882677176888926099744e+209,       /* 125! */
        2.372173242880046885677e+211,       /* 126! */
        3.012660018457659544810e+213,       /* 127! */
        3.856204823625804217357e+215,       /* 128! */
        4.974504222477287440390e+217,       /* 129! */
        6.466855489220473672507e+219,       /* 130! */
        8.471580690878820510985e+221,       /* 131! */
        1.118248651196004307450e+224,       /* 132! */
        1.487270706090685728908e+226,       /* 133! */
        1.992942746161518876737e+228,       /* 134! */
        2.690472707318050483595e+230,       /* 135! */
        3.659042881952548657690e+232,       /* 136! */
        5.012888748274991661035e+234,       /* 137! */
        6.917786472619488492228e+236,       /* 138! */
        9.615723196941089004197e+238,       /* 139! */
        1.346201247571752460588e+241,       /* 140! */
        1.898143759076170969429e+243,       /* 141! */
        2.695364137888162776589e+245,       /* 142! */
        3.854370717180072770522e+247,       /* 143! */
        5.550293832739304789551e+249,       /* 144! */
        8.047926057471991944849e+251,       /* 145! */
        1.174997204390910823948e+254,       /* 146! */
        1.727245890454638911203e+256,       /* 147! */
        2.556323917872865588581e+258,       /* 148! */
        3.808922637630569726986e+260,       /* 149! */
        5.713383956445854590479e+262,       /* 150! */
        8.627209774233240431623e+264,       /* 151! */
        1.311335885683452545607e+267,       /* 152! */
        2.006343905095682394778e+269,       /* 153! */
        3.089769613847350887959e+271,       /* 154! */
        4.789142901463393876336e+273,       /* 155! */
        7.471062926282894447084e+275,       /* 156! */
        1.172956879426414428192e+278,       /* 157! */
        1.853271869493734796544e+280,       /* 158! */
        2.946702272495038326504e+282,       /* 159! */
        4.714723635992061322407e+284,       /* 160! */
        7.590705053947218729075e+286,       /* 161! */
        1.229694218739449434110e+289,       /* 162! */
        2.004401576545302577600e+291,       /* 163! */
        3.287218585534296227263e+293,       /* 164! */
        5.423910666131588774984e+295,       /* 165! */
        9.003691705778437366474e+297,       /* 166! */
        1.503616514864999040201e+300,       /* 167! */
        2.526075744973198387538e+302,       /* 168! */
        4.269068009004705274939e+304,       /* 169! */
        7.257415615307998967397e+306        /* 170! */
	]

	log_factorials_table = [
    f64(0.000000000000000000000e+0),      /*   0! */
        0.000000000000000000000e+0,       /*   1! */
        6.931471805599453094172e-1,       /*   2! */
        1.791759469228055000812e+0,       /*   3! */
        3.178053830347945619647e+0,       /*   4! */
        4.787491742782045994248e+0,       /*   5! */
        6.579251212010100995060e+0,       /*   6! */
        8.525161361065414300166e+0,       /*   7! */
        1.060460290274525022842e+1,       /*   8! */
        1.280182748008146961121e+1,       /*   9! */
        1.510441257307551529523e+1,       /*  10! */
        1.750230784587388583929e+1,       /*  11! */
        1.998721449566188614952e+1,       /*  12! */
        2.255216385312342288557e+1,       /*  13! */
        2.519122118273868150009e+1,       /*  14! */
        2.789927138384089156609e+1,       /*  15! */
        3.067186010608067280376e+1,       /*  16! */
        3.350507345013688888401e+1,       /*  17! */
        3.639544520803305357622e+1,       /*  18! */
        3.933988418719949403622e+1,       /*  19! */
        4.233561646075348502966e+1,       /*  20! */
        4.538013889847690802616e+1,       /*  21! */
        4.847118135183522387964e+1,       /*  22! */
        5.160667556776437357045e+1,       /*  23! */
        5.478472939811231919009e+1,       /*  24! */
        5.800360522298051993929e+1,       /*  25! */
        6.126170176100200198477e+1,       /*  26! */
        6.455753862700633105895e+1,       /*  27! */
        6.788974313718153498289e+1,       /*  28! */
        7.125703896716800901007e+1,       /*  29! */
        7.465823634883016438549e+1,       /*  30! */
        7.809222355331531063142e+1,       /*  31! */
        8.155795945611503717850e+1,       /*  32! */
        8.505446701758151741396e+1,       /*  33! */
        8.858082754219767880363e+1,       /*  34! */
        9.213617560368709248333e+1,       /*  35! */
        9.571969454214320248496e+1,       /*  36! */
        9.933061245478742692933e+1,       /*  37! */
        1.029681986145138126988e+2,       /*  38! */
        1.066317602606434591262e+2,       /*  39! */
        1.103206397147573954291e+2,       /*  40! */
        1.140342117814617032329e+2,       /*  41! */
        1.177718813997450715388e+2,       /*  42! */
        1.215330815154386339623e+2,       /*  43! */
        1.253172711493568951252e+2,       /*  44! */
        1.291239336391272148826e+2,       /*  45! */
        1.329525750356163098828e+2,       /*  46! */
        1.368027226373263684696e+2,       /*  47! */
        1.406739236482342593987e+2,       /*  48! */
        1.445657439463448860089e+2,       /*  49! */
        1.484777669517730320675e+2,       /*  50! */
        1.524095925844973578392e+2,       /*  51! */
        1.563608363030787851941e+2,       /*  52! */
        1.603311282166309070282e+2,       /*  53! */
        1.643201122631951814118e+2,       /*  54! */
        1.683274454484276523305e+2,       /*  55! */
        1.723527971391628015638e+2,       /*  56! */
        1.763958484069973517152e+2,       /*  57! */
        1.804562914175437710518e+2,       /*  58! */
        1.845338288614494905025e+2,       /*  59! */
        1.886281734236715911873e+2,       /*  60! */
        1.927390472878449024360e+2,       /*  61! */
        1.968661816728899939914e+2,       /*  62! */
        2.010093163992815266793e+2,       /*  63! */
        2.051681994826411985358e+2,       /*  64! */
        2.093425867525368356464e+2,       /*  65! */
        2.135322414945632611913e+2,       /*  66! */
        2.177369341139542272510e+2,       /*  67! */
        2.219564418191303339501e+2,       /*  68! */
        2.261905483237275933323e+2,       /*  69! */
        2.304390435657769523214e+2,       /*  70! */
        2.347017234428182677427e+2,       /*  71! */
        2.389783895618343230538e+2,       /*  72! */
        2.432688490029827141829e+2,       /*  73! */
        2.475729140961868839366e+2,       /*  74! */
        2.518904022097231943772e+2,       /*  75! */
        2.562211355500095254561e+2,       /*  76! */
        2.605649409718632093053e+2,       /*  77! */
        2.649216497985528010421e+2,       /*  78! */
        2.692910976510198225363e+2,       /*  79! */
        2.736731242856937041486e+2,       /*  80! */
        2.780675734403661429141e+2,       /*  81! */
        2.824742926876303960274e+2,       /*  82! */
        2.868931332954269939509e+2,       /*  83! */
        2.913239500942703075662e+2,       /*  84! */
        2.957666013507606240211e+2,       /*  85! */
        3.002209486470141317540e+2,       /*  86! */
        3.046868567656687154726e+2,       /*  87! */
        3.091641935801469219449e+2,       /*  88! */
        3.136528299498790617832e+2,       /*  89! */
        3.181526396202093268500e+2,       /*  90! */
        3.226634991267261768912e+2,       /*  91! */
        3.271852877037752172008e+2,       /*  92! */
        3.317178871969284731381e+2,       /*  93! */
        3.362611819791984770344e+2,       /*  94! */
        3.408150588707990178690e+2,       /*  95! */
        3.453794070622668541074e+2,       /*  96! */
        3.499541180407702369296e+2,       /*  97! */
        3.545390855194408088492e+2,       /*  98! */
        3.591342053695753987760e+2,       /*  99! */
        3.637393755555634901441e+2,       /* 100! */
        3.683544960724047495950e+2,       /* 101! */
        3.729794688856890206760e+2,       /* 102! */
        3.776141978739186564468e+2,       /* 103! */
        3.822585887730600291111e+2,       /* 104! */
        3.869125491232175524822e+2,       /* 105! */
        3.915759882173296196258e+2,       /* 106! */
        3.962488170517915257991e+2,       /* 107! */
        4.009309482789157454921e+2,       /* 108! */
        4.056222961611448891925e+2,       /* 109! */
        4.103227765269373054205e+2,       /* 110! */
        4.150323067282496395563e+2,       /* 111! */
        4.197508055995447340991e+2,       /* 112! */
        4.244781934182570746677e+2,       /* 113! */
        4.292143918666515701285e+2,       /* 114! */
        4.339593239950148201939e+2,       /* 115! */
        4.387129141861211848399e+2,       /* 116! */
        4.434750881209189409588e+2,       /* 117! */
        4.482457727453846057188e+2,       /* 118! */
        4.530248962384961351041e+2,       /* 119! */
        4.578123879812781810984e+2,       /* 120! */
        4.626081785268749221865e+2,       /* 121! */
        4.674121995716081787447e+2,       /* 122! */
        4.722243839269805962399e+2,       /* 123! */
        4.770446654925856331047e+2,       /* 124! */
        4.818729792298879342285e+2,       /* 125! */
        4.867092611368394122258e+2,       /* 126! */
        4.915534482232980034989e+2,       /* 127! */
        4.964054784872176206648e+2,       /* 128! */
        5.012652908915792927797e+2,       /* 129! */
        5.061328253420348751997e+2,       /* 130! */
        5.110080226652360267439e+2,       /* 131! */
        5.158908245878223975982e+2,       /* 132! */
        5.207811737160441513633e+2,       /* 133! */
        5.256790135159950627324e+2,       /* 134! */
        5.305842882944334921812e+2,       /* 135! */
        5.354969431801695441897e+2,       /* 136! */
        5.404169241059976691050e+2,       /* 137! */
        5.453441777911548737966e+2,       /* 138! */
        5.502786517242855655538e+2,       /* 139! */
        5.552202941468948698523e+2,       /* 140! */
        5.601690540372730381305e+2,       /* 141! */
        5.651248810948742988613e+2,       /* 142! */
        5.700877257251342061414e+2,       /* 143! */
        5.750575390247102067619e+2,       /* 144! */
        5.800342727671307811636e+2,       /* 145! */
        5.850178793888391176022e+2,       /* 146! */
        5.900083119756178539038e+2,       /* 147! */
        5.950055242493819689670e+2,       /* 148! */
        6.000094705553274281080e+2,       /* 149! */
        6.050201058494236838580e+2,       /* 150! */
        6.100373856862386081868e+2,       /* 151! */
        6.150612662070848845750e+2,       /* 152! */
        6.200917041284773200381e+2,       /* 153! */
        6.251286567308909491967e+2,       /* 154! */
        6.301720818478101958172e+2,       /* 155! */
        6.352219378550597328635e+2,       /* 156! */
        6.402781836604080409209e+2,       /* 157! */
        6.453407786934350077245e+2,       /* 158! */
        6.504096828956552392500e+2,       /* 159! */
        6.554848567108890661717e+2,       /* 160! */
        6.605662610758735291676e+2,       /* 161! */
        6.656538574111059132426e+2,       /* 162! */
        6.707476076119126755767e+2,       /* 163! */
        6.758474740397368739994e+2,       /* 164! */
        6.809534195136374546094e+2,       /* 165! */
        6.860654073019939978423e+2,       /* 166! */
        6.911834011144107529496e+2,       /* 167! */
        6.963073650938140118743e+2,       /* 168! */
        7.014372638087370853465e+2,       /* 169! */
        7.065730622457873471107e+2,       /* 170! */
        7.117147258022900069535e+2,       /* 171! */
	]
)
